package com.briup.pai.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.briup.pai.common.constant.ModelConstant;
import com.briup.pai.common.enums.ModelStatusEnum;
import com.briup.pai.common.enums.ResultCodeEnum;
import com.briup.pai.common.enums.TrainingStatusEnum;
import com.briup.pai.common.exception.BriupAssert;
import com.briup.pai.common.utils.SecurityUtil;
import com.briup.pai.convert.ModelConvert;
import com.briup.pai.convert.TrainingLabelConvert;
import com.briup.pai.dao.ModelMapper;
import com.briup.pai.entity.dto.ModelSaveDTO;
import com.briup.pai.entity.po.Model;
import com.briup.pai.entity.vo.ModelDetailVO;
import com.briup.pai.entity.vo.ModelEchoVO;
import com.briup.pai.entity.vo.ModelPageVO;
import com.briup.pai.entity.vo.PageVO;
import com.briup.pai.service.IModelService;
import com.briup.pai.service.ITrainingDatasetService;
import com.briup.pai.service.ITrainingLabelService;
import com.briup.pai.service.ITrainingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@CacheConfig(cacheNames = ModelConstant.MODEL_CACHE_PREFIX)
public class ModelServiceImpl extends ServiceImpl<ModelMapper, Model> implements IModelService {
    @Autowired
    private ModelConvert modelConvert;
    @Autowired
    private ITrainingService trainingService;
    @Autowired
    private ITrainingDatasetService trainingDatasetService;
    @Autowired
    private ITrainingLabelService trainingLabelService;
    @Autowired
    private TrainingLabelConvert trainingLabelConvert;

    @Override
    public PageVO<ModelPageVO> getModelByPageAndCondition(Integer pageNum, Integer modelType) {
        //定义分页
        IPage<Model> page = new Page<>(pageNum, ModelConstant.MODEL_PAGE_SIZE);

        LambdaQueryWrapper<Model> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ObjectUtil.isNotEmpty(modelType),Model::getModelType, modelType)
                .orderByDesc(Model::getCreateTime);
        //查询
        List<Model> list = this.list(page, lqw);
        //转换对象
        List<ModelPageVO> modelPageVOList = modelConvert.po2ModelPageVOList(list);
       //构建返回值
        PageVO<ModelPageVO> objectPageVO = new PageVO<>();
        objectPageVO.setTotal(page.getTotal());
        objectPageVO.setData(modelPageVOList);
        return objectPageVO;

    }

    @Override
    public ModelEchoVO getModelById(Integer modelId) {
        //判断模型是否存在
        //对象转换
       return modelConvert.po2ModelEchoVO(BriupAssert.requireNotNull(this,Model::getId,modelId, ResultCodeEnum.DATA_NOT_EXIST));
    }

    @Override
    public ModelEchoVO addAndModifyModel(ModelSaveDTO modelSaveDTO) {
        //判断增加还是修改
        Integer modelId = modelSaveDTO.getModelId();
        Model model;
        if(ObjectUtil.isNull(modelId)){
            //验证名字不能重复
            BriupAssert.requireNull(this,Model::getModelName,modelSaveDTO.getModelName(), ResultCodeEnum.DATA_ALREADY_EXIST);
            //增加
            model = modelConvert.modelSaveDTO2Po(modelSaveDTO);
            model.setModelStatus(ModelStatusEnum.Unpublished.getStatus());
            model.setAccuracyRate(0.0);
            model.setLastModelVersion(0);
            model.setCreateBy(SecurityUtil.getUserId());
            model.setTrainingStatus(TrainingStatusEnum.NO_TRAINING.getStatus());
            this.save(model);
        }else {
            //模型必须存在
            Model temp = BriupAssert.requireNotNull(this,Model::getId,modelId, ResultCodeEnum.DATA_NOT_EXIST);
            //模型名称不能重复
            BriupAssert.requireNull(this,Model::getModelName,modelSaveDTO.getModelName(),
                    Model::getId,temp.getId(),ResultCodeEnum.DATA_ALREADY_EXIST);
            //模型分类不能修改
            BriupAssert.requireEqual(temp.getModelType(),modelSaveDTO.getModelType(),ResultCodeEnum.PARAM_IS_ERROR);
            //修改
            model = modelConvert.modelSaveDTO2Po(modelSaveDTO);
            this.updateById(model);
        }
        return null;
    }

    @Override
    public void removeModelById(Integer modelId) {
        //模型必须存在
        Model temp = BriupAssert.requireNotNull(this,Model::getId,modelId, ResultCodeEnum.DATA_NOT_EXIST);
        //只有未训练才能删除
        BriupAssert.requireEqual(temp.getTrainingStatus(),TrainingStatusEnum.NO_TRAINING.getStatus(),ResultCodeEnum.DATA_CAN_NOT_DELETE);
        this.removeById(modelId);

    }

    @Override
    public ModelDetailVO getModelDetailById(Integer modelId) {
        //模型必须存在
        Model model = BriupAssert.requireNotNull(this,Model::getId,modelId, ResultCodeEnum.DATA_NOT_EXIST);
        //转换为vo
        ModelDetailVO modelDetailVO = modelConvert.po2ModelDetailVO(model);
        //假如存在训练情况，查询模型训练的历史
//        if(ObjectUtil.notEqual(model.getTrainingStatus(),TrainingStatusEnum.NO_TRAINING.getStatus())){
//            //获取训练历史
//            LambdaQueryWrapper<Training> lqw = new LambdaQueryWrapper<>();
//            lqw.eq(Training::getModelId,modelId);
//            trainingService.list(lqw).stream().map(s -> {
//                ModelHistoryVO modelHistoryVO = new ModelHistoryVO();
//                modelHistoryVO.setEvaluateReport();
//                return modelHistoryVO;
//            });
//            for(Training training:list){
//                //根据训练查询训练结果
//                LambdaQueryWrapper<TrainingLabel> lqw2 = new LambdaQueryWrapper<>();
//                lqw2.eq(TrainingLabel::getTrainingId,training.getId());
//                List<ModelOperationResultVO> list1 = trainingLabelService.list(lqw2).stream().map(s -> trainingLabelConvert.po2ModelOperationResultVO(s)).toList();
//
//                ModelOperationResultVO modelOperationResultVO = trainingLabelConvert.po2ModelOperationResultVO();
//            }
//            modelDetailVO.setTrainingHistory();

   //     }
return null;

    }

    @Override
    public List<Integer> getDatasetIdsUsed() {
        return List.of();
    }
}